package util

import (
	"encoding/json"
	"errors"
	"fmt"
	"longmen/server/config/global"
	_const "longmen/server/pkg/common/helper/const"
	"longmen/server/pkg/common/helper/encrypt"
	"net/http"
	"runtime"
	"strings"
	"time"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"longmen/server/pkg/common/api_models"

	"github.com/go-playground/validator/v10"
	"github.com/golang/protobuf/proto"
	"github.com/labstack/echo/v4"
)

var key string

func SetKey(k string) {
	key = k
}

/*
返回当前系统设定的密钥，包含一个常量，和一个global里的
*/
func GetAESKey() string {
	return _const.JSON_KEY + key
}
func BuildSuccessRaw(c echo.Context, data interface{}, msg string) error {
	if msg == "" {
		msg = "SUCCESS"
	}
	return c.JSON(http.StatusOK, api_models.Response{
		Status: 0,
		Data:   data,
		Msg:    msg,
	})
}

func BuildPaySuccess(c echo.Context) error {

	return c.String(http.StatusOK, "success")
}
func BuildSuccess(c echo.Context, data interface{}, msg string) error {
	var err error
	if msg == "" {
		msg = "SUCCESS"
	}

	skipEncrypt := "/api/match/get55MatchList2"

	if c.Path() != skipEncrypt {
		prefix := fmt.Sprintf("%X", time.Now().Unix())
		if global.Config.GetInt("sys.apiEncrypt") == 1 && len(key) > 0 {
			b, _ := json.Marshal(data)
			data, err = encrypt.EncryptByAes(b, _const.JSON_KEY+key+prefix)
			if err == nil && len(data.(string)) != 0 {
				data = data.(string) + prefix
			}
		}
	}

	return c.JSON(http.StatusOK, api_models.Response{
		Status: 0,
		Data:   data,
		Msg:    msg,
	})
}

func BuildSuccessWithStatus(c echo.Context, data interface{}, msg string, status int) error {
	var err error
	if msg == "" {
		msg = "SUCCESS"
	}
	prefix := fmt.Sprintf("%X", time.Now().Unix())
	if global.Config.GetInt("sys.apiEncrypt") == 1 && len(key) > 0 {
		b, _ := json.Marshal(data)
		data, err = encrypt.EncryptByAes(b, _const.JSON_KEY+key+prefix)
		if err == nil && len(data.(string)) != 0 {
			data = data.(string) + prefix
		}
	}

	return c.JSON(http.StatusOK, api_models.Response{
		Status: status,
		Data:   data,
		Msg:    msg,
	})
}
func BuildHsqSuccess(c echo.Context, data interface{}, msg string) error {
	if msg == "" {
		msg = "SUCCESS"
	}
	return c.JSON(http.StatusOK, api_models.Response{
		Msg: msg,
	})
}
func BuildFail(c echo.Context, status int, msg string, err error) error {
	if err == nil {
		err = errors.New(msg)
	}
	if msg == "" {
		msg = "Failed"
	}
	if status == 0 { //逻辑健壮处理（系统约束0表示成功）
		status = 1
	}
	body, _ := c.Get("body").(string)
	after := strings.NewReplacer(" ", "", "\"", "", "\n", "").Replace(body)
	msg = strings.NewReplacer("rpc error: code = Unknown desc = ", "").Replace(msg)
	return c.JSON(http.StatusOK, api_models.Response{
		Status: status,
		Msg:    msg,
		ErrMsg: fmt.Sprintf("body:%s err:%s", after, err.Error()),
	})
}

func GrpcError(c echo.Context, code int, msg string, err error) error {
	statsErr := status.Convert(err)
	if statsErr.Code() == codes.DeadlineExceeded {
		msg = "route_timeout"
	}
	body, _ := c.Get("body").(string)
	return c.JSON(http.StatusOK, api_models.Response{
		Status: code,
		Msg:    statsErr.Message(),
		ErrMsg: fmt.Sprintf("body:%s err:%s", body, err.Error()),
	})
}

func BuildLoginTimeOut(c echo.Context, err error) error {
	return BuildFail(c, 2, "LOGIN TIMEOUT", err)
}

func BadParam(c echo.Context, err error) error {
	var (
		ok         bool
		defaultErr = errors.New("PARAM NOT MATCH CONDITION")
	)

	if err == nil {
		//goto OUTPUT
		return BuildFail(c, 1, "", defaultErr)
	}
	if _, ok = err.(validator.ValidationErrors); ok {
		if err = GetValidateError(err); err != nil {
			return BuildFail(c, 1, "BAD PARAM", err)
		}
	}

	//OUTPUT:
	return BuildFail(c, 1, "", defaultErr)
}

func ProtoBuf(c echo.Context, message proto.Message) error {
	bytes, err := proto.Marshal(message)
	if err != nil {
		return err
	}
	err = c.Blob(http.StatusOK, echo.MIMEApplicationProtobuf, bytes)
	if err != nil {
		return err
	}
	return nil
}

func GetSelfFuncName() string {
	pc, _, _, _ := runtime.Caller(1)
	return cleanUpFuncName(runtime.FuncForPC(pc).Name())
}

func GetFuncName(skips ...int) string {
	skip := 1
	if len(skips) > 0 {
		skip = skips[0] + 1
	}
	pc, _, _, _ := runtime.Caller(skip)
	return cleanUpFuncName(runtime.FuncForPC(pc).Name())
}

func cleanUpFuncName(funcName string) string {
	end := strings.LastIndex(funcName, ".")
	if end == -1 {
		return ""
	}
	return funcName[end+1:]
}
